﻿using System;
using System.Collections.Generic;
using System.Text;
using Reflection = System.Reflection;

namespace Xylee.Common
{
    public class Manufacture
    {
        /// <summary>
        /// Uses a generic pattern for creating factories 
        /// given the type instance objec that defines the 
        /// factory definition. This will use a simple implementation 
        /// of reflection to obtain the constructor and 
        /// generate based on that type.
        /// </summary>
        /// <param name="factoryType"></param>
        /// <returns></returns>
        public static ICommandFactory CreateFactory(Type factoryType)
        {
            // Handle nullable arguments
            if (factoryType == null)
                throw new ArgumentNullException("factoryType");

            // Get the contructor info from the type parameter
            Reflection.ConstructorInfo constructor = factoryType.GetConstructor(new Type[] { });

            // Handle private constructors
            if (constructor.IsPrivate)
                throw new Reflection.TargetException(string.Format("The constructor on the type {0} was " +
                          "private when it should be public in order to reflect. Please make this factory " +
                          "available to instantiate and create.", factoryType.Name),
                          new ArgumentException("Argument factoryType had invalid specifications, please " +
                                                "correct exception in order to create a factory at runtime."));
            // Handle abstract implementations
            if (constructor.IsAbstract)
                throw new Reflection.TargetException(string.Format("The constructor on the type {0} was " +
                          "abstract when it should be public and concrete in order to reflect. Please make this factory " +
                          "available to instantiate and create.", factoryType.Name),
                          new ArgumentException("Argument factoryType had invalid specifications, please " +
                                                "correct exception in order to create a factory at runtime."));

            // Create the factory and return it as an ICommandFactory
            object factory = constructor.Invoke(new object[] { });

            return (ICommandFactory)factory;
        }
    }
}
